import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import storage from 'store';
import { ElNotification } from 'element-plus';
import NProgress from 'nprogress';
import { storeToRefs } from 'pinia';
import { useUserStore } from '@/stores/user';
import { Result } from '@/model';

class Http {
  server;

  constructor(config: AxiosRequestConfig) {
    this.server = axios.create(config);

    // 错误处理器
    const errorHandler = (error: AxiosError) => {
      const status = error.response?.status;
      // 后台报错信息
      // @ts-ignore
      let msg = error.response?.data.msg;
      if (status === 401) {
        const userStore = useUserStore();
        const { isLogin } = storeToRefs(userStore);
        if (isLogin.value === null || isLogin.value) {
          userStore.$patch((state) => {
            state.isLogin = false;
          });
          userStore.logout().then();
        }
      } else {
        msg = msg || '系统内部错误，请联系管理员';
      }
      // 进度条关闭
      NProgress.done();
      // 标题使用error信息，message才是后台报错原因
      ElNotification.error({ title: '请求错误', message: msg });
      return Promise.reject(error);
    };

    // 请求拦截器
    // @ts-ignore
    this.server.interceptors.request.use((request: AxiosRequestConfig) => {
      // 进度条开始
      NProgress.start();
      // 如果 token 存在，让每个请求携带自定义 token
      const token = storage.get('ACCESS_TOKEN');
      if (token) {
        request.headers!.Authorization = token;
      }
      return request;
    }, errorHandler);

    // 响应拦截器
    this.server.interceptors.response.use((response: AxiosResponse<Result<any>>) => {
      const dataAxios = response.data;
      const { code, msg }: { code: number; msg: string } = dataAxios;
      // 进度条结束
      NProgress.done();
      // 这里的code是后台约定的状态吗，不是http状态码
      if (code === 200) {
        return dataAxios.data;
      }
      if (code === 401) {
        const userStore = useUserStore();
        // 是否已经退出登录跳转到登录页了？防止多次弹窗提醒未登录
        const { isLogin } = storeToRefs(userStore);
        if (isLogin.value === null || isLogin.value) {
          userStore.$patch((state) => {
            state.isLogin = false;
          });
          ElNotification.error({ title: '请求错误', message: msg });
          userStore.logout().then();
        }
        return Promise.reject(new Error(msg));
      }
      ElNotification.error({ title: '请求错误', message: msg });
      return Promise.reject(new Error(msg));
    }, errorHandler);
  }

  /**
   * get请求
   * @param url 请求地址
   * @param params 请求参数
   * @param headers 请求头
   */
  get<T>(url: string, params?: any, headers?: any): Promise<T> {
    return this.server.request<T>({
      url,
      params,
      method: 'GET',
      headers,
    });
  }

  /**
   * post请求
   * @param url 请求地址
   * @param data 请求参数
   * @param headers 请求头
   */
  post<T>(url: string, data?: any, headers?: any): Promise<T> {
    return this.server.request<T>({
      url,
      data,
      method: 'POST',
      headers,
    });
  }

  /**
   * delete请求
   * @param url 请求地址
   * @param params 请求参数
   * @param data 请求体
   * @param headers 请求头
   */
  delete<T>(url: string, params?: any, data?: any, headers?: any): Promise<T> {
    return this.server.request<T>({
      url,
      params,
      data,
      method: 'DELETE',
      headers,
    });
  }
}

const { VITE_APP_BASE_URL } = import.meta.env;
const config = {
  // API 请求的默认前缀
  baseURL: VITE_APP_BASE_URL as string,
  timeout: 60000,
};

const axiosHttp = new Http(config);

export default axiosHttp;
